/* Generated by Interface Builder */

#import "Pvc_Document.h"
#import "Pvc_Object.h"
#import <soundkit/Sound.h>
#import <appkit/appkit.h>
#import <cthreads.h>

@implementation Pvc_Document

#define COMPLAIN 

+ newFromFile:(char *)path
{
  fprintf(stderr,"Not implemented\n");
  return [self new];
}

static any_t runFunc(any_t obj)
{
  [((id)obj) runPvc];
  return 0;
}

-checkInputFile
{
  SNDSoundStruct *s;
  if (![pvcObject setInputFilename:(char *)[inputFileNameField stringValue]]){
	NXRunAlertPanel("Pvc","Could not open input file. Check name.",
			"OK",NULL,NULL,NULL);	
	return nil;
  } 
  s = [pvcObject insfh];
  if (s->dataFormat != SND_FORMAT_LINEAR_16 &&
      s->dataFormat != SND_FORMAT_DSP_DATA_16) {
	NXRunAlertPanel("Pvc","Input file must be in 16-bit format. Use mixsounds or RT to convert it.",
			"OK",NULL,NULL,NULL);	
	return nil;
  }
  if (s->channelCount != 1) {
	NXRunAlertPanel("Pvc","Input file must be in mono format. Use extractchannels to extract a channel.  Then run Pvc on each channel.  Finally, merge the channels with mixsounds or RT.",
			"OK",NULL,NULL,NULL);	
	return nil;
  }
  return self;  	
}

-runFromSender:sender
{
    float 	x;
    char msg[1024];
    if ([pvcObject status] != IDLE) {
	int i;
    	i = NXRunAlertPanel("Pvc",
			    "You're already computing.  Kill current computation?",
			    "Kill","Continue",NULL,NULL);
	if (i == NX_ALERTDEFAULT) {
	    [self killFromSender:self];
	    cthread_yield(); /* Let other thread finish. */
	} else if (i == NX_ALERTALTERNATE)
	  return nil;
    }
    if (![inputFileNameField stringValue])
    	if (![self openSoundFileFromSender:self])
		return nil;
    if (![outputFileNameField stringValue]) 
	if (![self openSoundFileFromSender:self])
		return nil;
    
    [pvcObject setDefaults];
    if (![self checkInputFile])
	return nil;
    [pvcObject setOutputFilename:(char *)[outputFileNameField stringValue]];

    [pvcObject N:[FFTsize intValue]];
    [pvcObject Nw:[windowSize intValue]];
    [pvcObject decim:[decimation intValue]];
    [pvcObject interp:[interpolation intValue]];

    x = [frequencyMultiplier floatValue];
    [pvcObject freqmlt:x];
    [pvcObject synt:0];       /* Noise gate */
    /* argument checking */
    if (![pvcObject checkArgs:msg]) {
	NXRunAlertPanel("Pvc",msg,"OK",NULL,NULL,NULL);
	return nil;    	
    }
    /* allocate NXzone ozone */
    [pvcObject allocateDataspace];
    /* create windows */
    [pvcObject makewindows];
    cthread_detach(cthread_fork(runFunc,(any_t) pvcObject));
    return self;
}

-setInterpolationFromSender:sender {return self;}
-setDecimationFromSender:sender {return self;}
-setFFTsizeFromSender:sender {return self;}
-setWindowFromSender:sender {return self;}
-setFrequencyFromSender:sender {return self;}

static BOOL getOpenPath(char *buf, char const *theType)
{
    static id	openPanel = nil;
    char const *fileTypes[2] = {0,0};

    if (!openPanel)
        openPanel = [OpenPanel new];
    if (theType && *theType)
	fileTypes[0] = theType;
    [NXApp setAutoupdate:NO];
    if ([openPanel runModalForTypes:fileTypes]) {
	strcpy(buf,[openPanel filename]);
	[NXApp setAutoupdate:YES];
	return YES;
    } else {
	[NXApp setAutoupdate:YES];
	return NO;
    }
}

static BOOL getSavePath(char *buf, char const *defaultPath)
{
    static id	savePanel = nil;
    BOOL	ok;
    char	dirName[1024], fileName[256];

    if (!savePanel) {
        const char *const types[2] = {"snd", NULL};
	
        savePanel = [SavePanel new];
        [savePanel setRequiredFileType:types[0]];
    }
    [NXApp setAutoupdate:NO];
    if (defaultPath && *defaultPath) {
	char *p;
	strcpy(dirName,defaultPath);
	if (p = rindex(dirName,'/')) {
	    strcpy(fileName, p+1);
	    *p = '\0';
	} else {
	    strcpy(fileName,defaultPath);
	    fileName[0] = '\0';
	}
	ok = [savePanel runModalForDirectory:dirName file:fileName];
    } else 
	ok = [savePanel runModal];
    [NXApp setAutoupdate:YES];
    if (ok) {
	strcpy(buf,[savePanel filename]);
	return YES;
    } else 
	return NO;
}

static DPSTimedEntryProc updateStatus( 
    DPSTimedEntry te,
    double now,
    void *userData )
{
    Pvc_Document *self;    
    self = userData;
    if (self->pvcObject) {
	    if ([self->pvcObject status] == IDLE) {
		    [self->statusField setStringValue:"done"];
		    [self->window display];
	    } else {
		char msg[1024];
		sprintf(msg,"running: %d%% computed",(int)([self->pvcObject howFar] * 100)); 
    		[self->statusField setStringValue:msg];
	    }
	}
    return 0;
}

- initFromFile:(const char *)file
{
    [super init];
    [NXApp loadNibSection:"Pvc_Document.nib" owner:self withNames:NO 
     fromZone:[self zone]];
    if (!file) 
      file = "untitled doc";
    [window setTitleAsFilename:file];
    pvcObject = [ [Pvc_Object alloc] init];
    [window makeKeyAndOrderFront:self];
    myTimedEntry = DPSAddTimedEntry(3.0,updateStatus,(int)self, 
    				    NX_BASETHRESHOLD);
    return self;
}

- init 
{
    [self initFromFile:NULL]; 
    return self;
  }

- openSoundFileFromSender:sender
{
    char pathname[1024];
    if (getOpenPath(pathname,"snd"))
      [inputFileNameField setStringValue:pathname];
    else return nil;
    return self;
}

- setOutputSoundFileFromSender:sender
{
    char pathname[1024];
    if (getSavePath(pathname,[sender stringValue])) {
      [outputFileNameField setStringValue:pathname];
    }
    else return nil;
    return self;
}

-playInputFromSender:sender 
{
  if (![self checkInputFile])
	return nil;
  SNDStartPlaying([pvcObject insfh],1,0, 1, NULL, NULL);
  return self;
}

-playOutputFromSender:sender 
{
  SNDStartPlaying([pvcObject outsfh],1,0, 1, NULL, NULL);
  return self;
}

-stopPlaying:sender
{
  SNDStop(1);
  return self;
}

-killFromSender:sender {
  if ([pvcObject status] != IDLE) {
	[pvcObject kill];
	[statusField setStringValue:"aborted"];
  }
  else NXRunAlertPanel("Pvc","Not computing.","OK",NULL,NULL,NULL);
  return self;
}

-pauseFromSender:sender {
  if ([pvcObject status] == PAUSED) {
    [(Pvc_Object *)pvcObject resume];
    [statusField setStringValue:"running"];

  }
  else if ([pvcObject status] != IDLE) {
  	[(Pvc_Object *)pvcObject pause];
        [statusField setStringValue:"paused"];
  }
  else {
  	NXRunAlertPanel("Pvc","Not computing.","OK",NULL,NULL,NULL);
	[sender setState:0];
  }
  return self;
}



@end

